﻿using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Video.FFMPEG;
//using Microsoft.AspNet.SignalR.Client;
using Microsoft.AspNetCore.SignalR.Client;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Qiniu.Http;
using Qiniu.IO;
using Qiniu.IO.Model;
using Qiniu.RSF;
using Qiniu.RSF.Model;
using Qiniu.Util;
using QRCoder;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.ExceptionServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WebSocketSharp;
using WebSocketSharp.Server;

namespace AforgeDemo
{

    public partial class Form1 : Form
    {
        //用来操作摄像头 
        private VideoCaptureDevice Camera = null;
        //用来把每一帧图像编码到视频文件
        private VideoFileWriter VideoOutPut = new VideoFileWriter();
        private int Seconds;
        private bool Record = false;

        private static string timeSpan;
        private static string path;
        private static string uploadName;
        private static bool getPic = false;

        private int totalSeconds = 9;
        private int AverageFrameRate = 25;
        private int cameraIndex = 2;
        private int number = 0;
        //Socket
        //private static IHubProxy HubProxy { get; set; }
        HubConnection Connection;
        //开始摄像委托
        public delegate void ButtonClick();
        public ButtonClick buttonClick;

        public Form1()
        {
            InitializeComponent();
            if (Screen.AllScreens.Count() > 1)
            {
                this.StartPosition = FormStartPosition.Manual;
                this.Location = new Point(Screen.AllScreens[1].Bounds.Left, Screen.AllScreens[1].Bounds.Top);
                this.ControlBox = false;   // 设置不出现关闭按钮
                this.FormBorderStyle = FormBorderStyle.None;
                this.WindowState = FormWindowState.Maximized;
            }

            Qiniu.Common.Config.AutoZone(QiniuSetting.QiniuAccessKey, QiniuSetting.QiniuBucket, true);
            Connection = new HubConnectionBuilder()
                .WithUrl("http://mm.tiaodu.cn/cameraHub")
                .Build();
            connectServer();
            //HubProxy = Connection.CreateHubProxy("SocketHub");
            //Connection.Start();
            //HubProxy.On<string>("beginRecord", (m) =>
            //{
            //    Console.WriteLine(m);
            //    if(m == "开始录像")
            //    {
            //        buttonClick = new ButtonClick(clickTest);
            //        BeginInvoke(buttonClick);
            //    }
            //});
            Connection.Closed += async (error) =>
            {
                await Reconnect();
            };

            Thread checkThread = new Thread(new ThreadStart(CheckFile));
            checkThread.Start();
        }

        private async Task Reconnect()
        {
            try
            {
                Console.WriteLine("断线重连...");
                await Task.Delay(new Random().Next(0, 5) * 1000);
                await Connection.StartAsync();
            }
            catch (HttpRequestException ex)
            {
                Console.WriteLine(ex);
                await Reconnect();
            }

        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void timer1_Tick(object sender, EventArgs e)
        {

            pictureBox1.Refresh();

        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            //获取摄像头列表
            var devs = new FilterInfoCollection(FilterCategory.VideoInputDevice);

            //实例化设备控制类
            //Camera = new VideoCaptureDevice(devs[0].MonikerString);

            //配置录像参数(宽,高,帧率,比特率,等)
            //Camera.VideoResolution = Camera.VideoCapabilities[0];
            foreach (FilterInfo res in devs)
            {
                cameraList.Items.Add(res.Name);
            }
            cameraList.SelectedIndex = cameraIndex;
            //设置回调,aforge会不断从这个回调推出图像数据
            //Camera.NewFrame += Camera_NewFrame;

            //开始
            //Camera.Start();

            //打开录像文件(如果没有则创建,如果有也会清空).
            //VideoOutPut.Open("E:/VIDEO.MP4", Camera.VideoResolution.FrameSize.Width, Camera.VideoResolution.FrameSize.Height, Camera.VideoResolution.AverageFrameRate, VideoCodec.MPEG4, Camera.VideoResolution.BitCount);
        }

        //图像缓存
        private Bitmap bmp = new Bitmap(1, 1);
        private Bitmap savebmp = new Bitmap(1, 1);
        private Bitmap videobmp = new Bitmap(1, 1);
        ////摄像头输出回调
        [HandleProcessCorruptedStateExceptions]
        private void Camera_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            eventArgs.Frame.RotateFlip(RotateFlipType.Rotate90FlipNone);
            //写到文件
            if (Record)
            {
                lock (videobmp)
                {
                    try
                    {
                        videobmp.Dispose();
                        videobmp = eventArgs.Frame.Clone() as Bitmap;
                        VideoOutPut.WriteVideoFrame(videobmp);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex);
                    }
                }

            }
            if (getPic)
            {
                lock (savebmp)
                {
                    getPic = false;
                    savebmp.Dispose();
                    savebmp = eventArgs.Frame.Clone() as Bitmap;
                    savebmp.Save(string.Format("D:\\video\\Recording{0}_{1}_{2}.jpg", timeSpan, Guid, 9 - Seconds), ImageFormat.Jpeg);
                    FileInfo f = new FileInfo(string.Format("D:\\video\\Recording{0}_{1}_{2}.jpg", timeSpan, Guid, 9 - Seconds));
                    string recordedName = string.Format("{0}_{1}_{2}.jpg", timeSpan, Guid, 9 - Seconds);
                    f.MoveTo(string.Format("D:\\video\\{0}", recordedName));
                }
            }

            lock (bmp)
            {
                //释放上一个缓存
                bmp.Dispose();
                //保存一份缓存

                bmp = eventArgs.Frame.Clone() as Bitmap;
                //bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //停摄像头
            Camera.Stop();

            //关闭录像文件,如果忘了不关闭,将会得到一个损坏的文件,无法播放
            VideoOutPut.Close();
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            //if (bmp == null) return;

            lock (bmp)
            {
                //bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                e.Graphics.DrawImage(bmp, 0, 0);
            }
        }

        private void cameraList_SelectedIndexChanged(object sender, EventArgs e)
        {
            //暂时禁用选择摄像头
            var devs = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            foreach (FilterInfo dev in devs)
            {
                if (dev.Name == cameraList.SelectedItem.ToString())
                {
                    if (Camera != null)
                        Camera.Stop();

                    Camera = new VideoCaptureDevice(dev.MonikerString);
                    foreach (var r in Camera.VideoCapabilities)
                    {
                        if (r.FrameSize.Width == 1280 && r.FrameSize.Height == 720)
                        {
                            Camera.VideoResolution = r;
                            break;
                        }
                        else
                        {
                            Camera.VideoResolution = Camera.VideoCapabilities[0];
                        }
                    }
                    //设置回调,aforge会不断从这个回调推出图像数据
                    Camera.NewFrame += Camera_NewFrame;
                    //开始
                    Camera.Start();
                }
            }
        }

        private void clickTest()
        {
            if (!Record)
            {
                Seconds = totalSeconds;

                path = "Recording" + timeSpan + "_" + Guid + ".mp4";

                VideoOutPut.Open(string.Format("D:\\video\\{0}", path), Camera.VideoResolution.FrameSize.Height, Camera.VideoResolution.FrameSize.Width, AverageFrameRate, VideoCodec.MPEG4, 3000000);
                Record = true;
                timer2.Start();
                //begin.Text = "停止";
            }
            else
            {

                //VideoOutPut.Close();

                //begin.Text = "录制";
            }
        }

        private async void connectServer()
        {
            //begin.PerformClick();
            if (!connecting)
            {
                //接收服务器推送过来的指令
                Connection.On<string, string, string>("ReceiveCommand", (customerGuid, command, commandSendTime) =>
                {
                    if (Guid == null)
                    {
                        Guid = customerGuid;
                        timeSpan = commandSendTime;
                        if (command == "start_record")
                        {
                            buttonClick = new ButtonClick(clickTest);
                            BeginInvoke(buttonClick);
                        }
                    }

                    Console.WriteLine(customerGuid + ":" + command + ":" + commandSendTime);
                    Action<string> action = (data) =>
                    {
                        commandLabel.Text = data.ToString();
                    };
                    Invoke(action, command);
                });
                try
                {
                    //打开SginalR链接
                    await Connection.StartAsync();
                    connecting = true;
                    buttonConnect.Text = "释放控制";
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }

        public static void CheckFile()
        {
            while (true)
            {
                string path = "D:\\video";
                DirectoryInfo root = new DirectoryInfo(path);
                //Console.WriteLine(root.GetFiles().FirstOrDefault().Name);
                foreach (FileInfo f in root.GetFiles())
                {
                    Regex r = new Regex("^[0-9]{18}");
                    if (r.IsMatch(f.Name))
                    {
                        Console.WriteLine(f.Name);
                        string newName = "Uploading_" + f.Name;
                        f.MoveTo(string.Format("D:\\video\\{0}", newName));
                        //uploadName = newName;
                        //UploadFile(newName);

                        Thread uploadThread = new Thread(new ParameterizedThreadStart(UploadFile));
                        uploadThread.Start(newName);

                    }
                }


            }
        }

        //上传
        public static async void UploadFile(object newName)
        {
            Regex end = new Regex(".jpg$");

            Mac mac = new Mac(QiniuSetting.QiniuAccessKey, QiniuSetting.QiniuSecurityKey);
            string name = newName.ToString();
            string[] strArray = name.Split('_');
            string uploadTimeSpan = strArray[1];

            string saveKey;
            string localFile = "D:\\video\\" + name;

            if (end.IsMatch(name))
            {
                saveKey = uploadTimeSpan + "_" + strArray[3];
            }
            else
            {
                saveKey = uploadTimeSpan + ".mp4";
            }


            PutPolicy putPolicy = new PutPolicy();

            putPolicy.Scope = QiniuSetting.QiniuBucket;
            putPolicy.SetExpires(3600);

            string jstr = putPolicy.ToJsonString();
            string token = Auth.CreateUploadToken(mac, jstr);

            UploadManager um = new UploadManager();

            try
            {
                HttpResult result = um.UploadFile(localFile, saveKey, token);

                //Console.WriteLine(result);

                if (result.Code == 200)
                {
                    Console.WriteLine("上传成功");
                    PostRequest(name);
                }
                else
                {
                    Console.WriteLine("QINIU上传失败，重试...");
                    await Task.Delay(new Random().Next(0, 5) * 1000);
                    UploadFile(name);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                await Task.Delay(new Random().Next(0, 5) * 1000);
                UploadFile(name);
            }

            //HubProxy.Invoke("sendSuccess", "录像完成key:" + result.Text);

            //暂不需要转码
            //PfopAndSave();

        }

        public static async void PostRequest(string name)
        {
            Regex end = new Regex(".jpg$");
            string[] strArray = name.Split('_');
            string uploadTimeSpan;
            string uploadGuid;
            string postDataStr;
            if (end.IsMatch(name))
            {
                uploadTimeSpan = strArray[1];
                uploadGuid = strArray[2];
                var video = new
                {
                    customer_guid = uploadGuid,
                    share_title = "记忆镜",
                    share_url = "https://mm.tiaodu.cn",
                    video_url = "http://mmvideo.tiaodu.cn/" + uploadTimeSpan + "_" + strArray[3],
                    command_send_time = uploadTimeSpan,
                    video_type = "Capture"
                };
                var postData = new
                {
                    video = video
                };
                postDataStr = JsonConvert.SerializeObject(postData);
            }
            else
            {
                uploadTimeSpan = strArray[1];
                uploadGuid = strArray[2].Split('.')[0];
                var video = new
                {
                    customer_guid = uploadGuid,
                    share_title = "记忆镜",
                    share_url = "https://mm.tiaodu.cn",
                    video_url = "http://mmvideo.tiaodu.cn/" + uploadTimeSpan + ".mp4",
                    command_send_time = uploadTimeSpan,
                    video_type = "Video"
                };
                var postData = new
                {
                    video = video
                };
                postDataStr = JsonConvert.SerializeObject(postData);
            }



            string strURL = "https://mm.tiaodu.cn/api/videos/create";
            HttpWebRequest request;
            request = (HttpWebRequest)WebRequest.Create(strURL);
            request.Method = "POST";
            request.ContentType = "application/json";

            byte[] payload;
            payload = Encoding.UTF8.GetBytes(postDataStr);
            request.ContentLength = payload.Length;

            Stream writer = request.GetRequestStream();
            writer.Write(payload, 0, payload.Length);
            writer.Close();

            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    Stream s;
                    s = response.GetResponseStream();
                    string strValue = "";
                    StreamReader Reader = new StreamReader(s, Encoding.UTF8);
                    strValue = Reader.ReadToEnd();

                    Console.WriteLine(strValue);
                    FileInfo f = new FileInfo(string.Format("D:\\video\\{0}", name));
                    string doneName = "Done_" + name;
                    f.MoveTo(string.Format("D:\\video\\done\\{0}", doneName));
                }
                else
                {
                    Console.WriteLine("上传失败，重试...");
                    await Task.Delay(new Random().Next(0, 5) * 1000);
                    PostRequest(name);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                await Task.Delay(new Random().Next(0, 5) * 1000);
                PostRequest(name);
            }


            //uploadName = null;

        }

        //转码
        public void PfopAndSave()
        {
            string key = timeSpan + ".mp4";
            string dstKey = "new" + timeSpan + ".mp4";
            string saveAsUri = Base64.UrlSafeBase64Encode(QiniuSetting.QiniuBucket + ":" + dstKey);
            string fopM = "avthumb/vcodec/libx264";
            string fops = fopM + "%7csaveas/" + saveAsUri;

            Mac mac = new Mac(QiniuSetting.QiniuAccessKey, QiniuSetting.QiniuSecurityKey);

            OperationManager ox = new OperationManager(mac);
            PfopResult result = ox.Pfop(QiniuSetting.QiniuBucket, key, fops, null, null, false);
            Console.WriteLine(result);
            Console.WriteLine("转码成功");
            string persistentId = result.PersistentId;
            HttpResult pr = OperationManager.Prefop(persistentId);
            Console.WriteLine(pr);

        }

        private void begin_Click(object sender, EventArgs e)
        {
            //if(!Record)
            //{
            //    Seconds = 9;

            //    path = "Recording" + timeSpan + "_" + Guid + ".mp4";

            //    VideoOutPut.Open(string.Format("D:\\video\\{0}", path), Camera.VideoResolution.FrameSize.Height, Camera.VideoResolution.FrameSize.Width, Camera.VideoResolution.AverageFrameRate, VideoCodec.MPEG4, 3000000);
            //    Record = true;
            //    begin.Enabled = false;
            //    timer2.Start();
            //    //begin.Text = "停止";
            //}
            //else
            //{

            //    //VideoOutPut.Close();

            //    //begin.Text = "录制";
            //}
        }

        //计时录制
        private void timer2_Tick(object sender, EventArgs e)
        {
            Seconds--;
            if (Seconds < 9 && Seconds > 0)
            {
                getPic = true;
            }

            if (Seconds <= 0)
            {
                timer2.Stop();
                Record = false;
                VideoOutPut.Close();

                FileInfo f = new FileInfo(string.Format("D:\\video\\{0}", path));
                var newPath = timeSpan + "_" + Guid + ".mp4";
                f.MoveTo(string.Format("D:\\video\\{0}", newPath));
                Thread release = new Thread(new ThreadStart(GetRequest));
                release.Start();

                //Thread workerThread = new Thread(new ThreadStart(UploadFile));
                //workerThread.Start();


                //HubProxy.Invoke("sendSuccess", "录像完成");
                return;
            }
        }

        private static void GetRequest()
        {
            string strURL = "https://mm.tiaodu.cn/api/client/free/0";
            HttpWebRequest request;
            request = (HttpWebRequest)WebRequest.Create(strURL);
            request.Method = "GET";
            request.ContentType = "application/json";

            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    Console.WriteLine("重试释放...");
                    GetRequest();
                }
                else
                {
                    Stream s;
                    s = response.GetResponseStream();
                    string strValue = "";
                    StreamReader Reader = new StreamReader(s, Encoding.UTF8);
                    strValue = Reader.ReadToEnd();


                    JObject jo = (JObject)JsonConvert.DeserializeObject(strValue);
                    if (jo["result"].ToString() == "ok")
                    {
                        Console.WriteLine("释放成功：" + strValue);
                        Guid = null;
                        timeSpan = null;
                    }
                }
            }
            catch (Exception ex)
            {
                GetRequest();
            }

        }
        private static bool connecting = false;
        private static string Guid = null;
        private async void buttonConnect_Click(object sender, EventArgs e)
        {
            //连接服务器并监听指令
            if (!connecting)
            {
                //接收服务器推送过来的指令
                Connection.On<string, string, string>("ReceiveCommand", (customerGuid, command, commandSendTime) =>
                {
                    if (Guid == null)
                    {
                        Guid = customerGuid;
                        timeSpan = commandSendTime;
                        if (command == "start_record")
                        {
                            buttonClick = new ButtonClick(clickTest);
                            BeginInvoke(buttonClick);
                        }
                    }

                    Console.WriteLine(customerGuid + ":" + command + ":" + commandSendTime);
                    Action<string> action = (data) =>
                    {
                        commandLabel.Text = data.ToString();
                    };
                    Invoke(action, command);
                });

                //生成和小程序控制端配对的二维码,一次一码防止盗录
                //Connection.On<string>("ShowQRCode", (connectionId) =>
                //{
                //    Console.WriteLine(connectionId);
                //    var QRCodeFile = GenQRCode(connectionId);
                //    QRCodeBox.Image = System.Drawing.Image.FromStream(QRCodeFile);
                //});

                try
                {
                    //打开SginalR链接
                    await Connection.StartAsync();
                    connecting = true;
                    buttonConnect.Text = "释放控制";
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            else
            {
                try
                {
                    //打开SginalR链接
                    await Connection.StopAsync();
                    connecting = false;
                    buttonConnect.Text = "开始配对";
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }

        private MemoryStream GenQRCode(string str)
        {
            QRCodeGenerator qrGenerator = new QRCoder.QRCodeGenerator();
            QRCodeData qrCodeData = qrGenerator.CreateQrCode(str, QRCodeGenerator.ECCLevel.Q);
            QRCode qrcode = new QRCode(qrCodeData);

            Bitmap qrCodeImage = qrcode.GetGraphic(3, Color.Black, Color.White, null, 15, 6, false);
            MemoryStream ms = new MemoryStream();
            qrCodeImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            return ms;
        }
    }
}